package com.xd.shading.config.sharding;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.driver.api.ShardingSphereDataSourceFactory;
import org.apache.shardingsphere.infra.config.algorithm.ShardingSphereAlgorithmConfiguration;
import org.apache.shardingsphere.sharding.api.config.ShardingRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.rule.ShardingTableRuleConfiguration;
import org.apache.shardingsphere.sharding.api.config.strategy.sharding.StandardShardingStrategyConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

@Slf4j
@Configuration
public class ShardingConfig {

    @Value("${spring.shardingsphere.datasource.db1.url}")
    private String url;

    @Value("${spring.shardingsphere.datasource.db1.username}")
    private String username;

    @Value("${spring.shardingsphere.datasource.db1.password}")
    private String password;

    @Value("${spring.shardingsphere.datasource.db1.driver-class-name}")
    private String driverClassName;


    @Bean("shardingDB")
    public DataSource shardingDataSource() throws SQLException {
        ShardingRuleConfiguration shardingRuleConfig = new ShardingRuleConfiguration();
        shardingRuleConfig.getTables().add(getShardingTableRuleConfig("t_order"));
        //第二个分表
        shardingRuleConfig.getTables().add(getShardingTableRuleConfig("t_houses"));
        // 绑定表
        shardingRuleConfig.getBindingTableGroups().addAll(Arrays.asList("t_order", "t_houses"));

        // 配置分库算法
        Properties dbShardingAlgorithmrProps = new Properties();
        dbShardingAlgorithmrProps.setProperty("strategy", "STANDARD");
        dbShardingAlgorithmrProps.setProperty("algorithmClassName", "com.xd.shading.config.sharding.DbStandardShardingAlgorithm");
        // 设置分库策略
        shardingRuleConfig.getShardingAlgorithms().put("dbShardingAlgorithm", new ShardingSphereAlgorithmConfiguration("CLASS_BASED", dbShardingAlgorithmrProps));


        // 配置分表算法
        Properties tableShardingAlgorithmrProps = new Properties();
        tableShardingAlgorithmrProps.setProperty("strategy", "STANDARD");
        tableShardingAlgorithmrProps.setProperty("algorithmClassName", "com.xd.shading.config.sharding.TableStandardShardingAlgorithm");
        // 设置分表策略
        shardingRuleConfig.getShardingAlgorithms().put("tableShardingAlgorithm", new ShardingSphereAlgorithmConfiguration("CLASS_BASED", tableShardingAlgorithmrProps));

        // 配置额外参数，如改写后的sql展示
        Properties properties = new Properties();
        properties.put("sql-show", true);
        return ShardingSphereDataSourceFactory.createDataSource(createDataSourceMap(), Collections.singletonList(shardingRuleConfig), properties);
    }




    /**
     * 创建分表规则 必须项
     * @param logicTable
     * @return
     */
    private ShardingTableRuleConfiguration getShardingTableRuleConfig(String logicTable) {
        //这里的database名称对应下面的key名称
        ShardingTableRuleConfiguration shardingTableRuleConfiguration =
                new ShardingTableRuleConfiguration(logicTable, "db1." + logicTable + "_$->{0..2}");
        // 配置分库策略
        shardingTableRuleConfiguration.setDatabaseShardingStrategy(
                new StandardShardingStrategyConfiguration("id", "dbShardingAlgorithm"));
        // 配置分表策略
        shardingTableRuleConfiguration.setTableShardingStrategy(
                new StandardShardingStrategyConfiguration("id", "tableShardingAlgorithm"));
        return shardingTableRuleConfiguration;
    }


    public Map<String, DataSource> createDataSourceMap() throws SQLException {
        //这里的key名称对应上面的database名称
        final Map<String, DataSource> dbMap = new HashMap<>();
        dbMap.put("db1", createShardingDataSource());
        return dbMap;
    }

    private DataSource createShardingDataSource() throws SQLException {
        DruidDataSource datasource = DruidDataSourceBuilder.create().build();
        datasource.setUrl(url);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);
        log.info("shardingdb init");
        return datasource;
    }

}
